#include <stdio.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>

int main(int argc, char *argv[])
{
    int ret;
    struct sockaddr_nl *nl; // 定义一个指向 struct sockaddr_nl 结构体的指针 nl
    int len = 0;
    char buf[4096] = {0}; // 数据接收缓冲区
    int i = 0;

    bzero(nl, sizeof(struct sockaddr_nl)); // 将 nl 指向的内存区域清零， 确保结构体的字段初始化为 0
    nl->nl_family = AF_NETLINK;            // 设置 nl 结构体的 nl_family 字段为 AF_NETLINK， 指定地址族为 Netlink
    nl->nl_pid = 0;                        // 设置 nl 结构体的 nl_pid 字段为 0， 表示目标进程 ID 为 0， 即广播给所有进程
    nl->nl_groups = 1;                     // 设置 nl 结构体的 nl_groups 字段为 1， 表示只接收基本组的内核事件

    int socket_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT); // 创建一个 Netlink套接字
    if (socket_fd < 0)
    {
        printf("socket error\n");
        return -1;
    }

    ret = bind(socket_fd, (struct sockaddr *)nl, sizeof(struct sockaddr_nl)); // 使用 bind 函数将 socket_fd 套接字与 nl 地址结构体绑定在一起
    if (ret < 0)
    {
        printf("bind error\n");
        return -1;
    }

    while (1)
    {
        bzero(buf, 4096);                     // 将缓冲区 buf 清零， 确保数据接收前的初始化
        len = recv(socket_fd, &buf, 4096, 0); // 从 socket_fd 套接字接收数据， 存储到缓冲区 buf 中，最大接收字节数为 4096

        for (i = 0; i < len; i++)
        {
            if (*(buf + i) == '\0')
            {
                buf[i] = '\n'; // 如果接收到的数据中有 '\0' 字符， 将其替换为 '\n'， 以便在打印时换行显示
            }
        }

        printf("%s\n", buf); // 打印接收到的数据
    }

    return 0;
}
